//
// Created by Administrator on 2022/10/14 0014.
//

#ifndef ONIX_TASK_H
#define ONIX_TASK_H

#include <onix/types.h>
#include <onix/bitmap.h>
#include <onix/list.h>

#define KERNEL_USER         0
#define NORMAL_USER         1
#define TASK_NAME_LENGTH    16

typedef enum task_state_t
{
    TASK_INIT,
    TASK_RUNNING,
    TASK_READY,
    TASK_BLOCKED,
    TASK_SLEEPING,
    TASK_WAITING,
    TASK_DIED
} task_state_t;

// i386 System V ABI
// IN: ebx, esi, edi, ebp, esp
// OUT: eax, ecx, edx
typedef struct task_frame_t
{
    u32 edi;
    u32 esi;
    u32 ebx;
    u32 ebp;
    void (*eip)(void);
} __attribute__((packed)) task_frame_t;

typedef struct task_t
{
    // 内核栈
    task_frame_t *stack;
    // 任务阻塞节点
    list_node_t node;
    // 状态
    task_state_t state;
    // 优先级
    u32 priority;
    // 剩余时间片
    u32 ticks;
    // 上次执行时全局时间片
    u32 jiffies;
    // 任务名称
    u32 name[TASK_NAME_LENGTH];
    // 用户ID
    u32 uid;
    // 任务ID
    pid_t pid;
    // 父任务ID
    pid_t ppid;
    // 页目录物理地址
    u32 pde;
    // 进程虚拟内存位图
    struct bitmap_t *vmap;
    // 进程堆内存最高地址
    u32 brk;
    // 进程特殊状态
    int status;
    // 进程等待的PID
    pid_t waitpid;
    // 内核模数
    u32 magic;
} __attribute__((packed)) task_t;

// 中断帧
typedef struct intr_frame_t
{
    u32 vector;

    u32 edi;
    u32 esi;
    u32 ebp;
    // 虽然 pushad 把 esp 也压入，但 esp 是不断变化的，所以会被 popad 忽略
    u32 esp_dummy;

    u32 ebx;
    u32 edx;
    u32 ecx;
    u32 eax;

    u32 gs;
    u32 fs;
    u32 es;
    u32 ds;

    u32 vector0;

    u32 error;

    u32 eip;
    u32 cs;
    u32 eflags;
    u32 esp;
    u32 ss;
} intr_frame_t;

typedef void target_t();

void task_init();

// 线程调度
void schedule();

task_t *running_task();

void task_yield();

void task_block(task_t *task, list_t *list, task_state_t state);

void task_unblock(task_t *task);

void task_sleep(u32 ms);

void task_wakeup();

void task_to_user_mode(target_t target);

pid_t sys_getpid();

pid_t sys_getppid();

pid_t task_fork();

void task_exit(int status);

pid_t task_waitpid(pid_t pid, int32 *status);

#endif //ONIX_TASK_H
